home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Skunkware 98
/
Skunkware 98.iso
/
src
/
shellutil
/
zip21.tar.gz
/
zip21.tar
/
zip-2.1
/
amiga
/
match_68.a
< prev
next >
Wrap
Text File
|
1996-04-01
|
8KB
|
266 lines
; This is a 68000 assembly language version of the Zip function
; longest_match(). It is written for any 680x0 based computer, but at this
; time the feature for runtime testing of CPU type is only supported for the
; Amiga. Hopefully a similar test for the Macintosh is possible, and for any
; other system that supports both 68000 and 68020+ CPUs. This is written by
; Paul Kienitz, partially derived from a simpler version by Carsten Steger,
; derived in turn from a 386 assembly function by Jean-loup Gailly and Uwe
; Rommel... but also based directly on the C original. No rights reserved.
;
; The main difference of this from other longest_match() implementations is
; that it includes both byte based and word based versions of the function,
; and various symbols can be defined to select whether to use one routine or
; the other, or to do a platform-specific test at runtime. The symbols that
; can be used to select behavior are as follows:
;
; CPU020 if defined, use 68020 instructions always
; CPUTEST if defined, check at runtime for CPU type. Another symbol
; specifying the platform-specific test must be used with this.
; If neither of these is defined, use 68000 instructions only.
; AMIGA use Amiga-specific test for 68020, if CPUTEST defined. Also
; tells it to let a0/a1/d1 be clobbered by functions.
; ATSIGN define entry symbols in @foo form as well as _foo, with
; @longest_match taking its parm in d0 instead of on the stack.
; WSIZE if defined, determines the sliding window size for deflate;
; the default is 32K. If you have reduced WSIZE for the C code,
; make sure that this module is assembled with an equivalent
; "-dWSIZE=<whatever>" (or "-e...") switch.
;
; NOTE: no provision is made for 16 bit ints. All external int variables are
; treated as 32 bit values. This also assumes that longest_match's result is
; returned in D0.
IFND CPU020
IFND CPUTEST
CPU000 equ 1
ENDC
ENDC
; global variables:
xref _max_chain_length ; unsigned int
xref _prev_length ; unsigned int
xref _match_start ; unsigned int
xref _strstart ; unsigned int
xref _good_match ; signed int
xref _nice_match ; signed int
xref _window ; array of unsigned char
xref _prev ; array of unsigned short
; our entry points:
xdef _match_init ; void match_init(void);
xdef _longest_match ; int longest_match(unsigned cur_match);
IFD ATSIGN
xdef @match_init ; for SAS assembler
xdef @longest_match ; ditto
ENDC
; flag variable for remembering CPU type:
IFD CPUTEST
section cpuflag,data
is020: ds.w 1
ENDC
section match,code
_match_init:
IFD ATSIGN
@match_init:
ENDC
IFD CPUTEST ; now check for platform type
IFD AMIGA ; Amiga specific test for '020 CPU:
xref _SysBase
NOLIST
INCLUDE 'exec/execbase.i'
LIST
clr.w is020 ; default value is 68000
move.l _SysBase,a0
btst #AFB_68020,AttnFlags+1(a0)
beq.s cheap
move.w #1,is020
cheap:
ELSE ; !AMIGA
!! Write an '020-detector for your system here!
ENDC ; AMIGA
ENDC ; CPUTEST
rts ; match_init consists only of rts if CPUTEST unset
IFD AMIGA
SAVEREGS reg d3-d7/a2/a3/a5 ; don't protect d0/d1/a0/a1
ELSE
SAVEREGS reg d1/d3-d7/a0-a3/a5 ; protect all but d0 return val
ENDC
Cur_Match equr d0 ; Must be in d0!
Best_Len equr d1
Scan_Start equr d3
Scan_End equr d4
Limit equr d5
Chain_Length equr d6
Scan_Test equr d7
Scan equr a0
Match equr a1
Prev_Address equr a2
Scan_Ini equr a3
Match_Ini equr a5
MAX_MATCH equ 258
MIN_MATCH equ 3
IFND WSIZE
WSIZE equ 32768
ENDC
MAX_DIST equ WSIZE-MAX_MATCH-MIN_MATCH-1
_longest_match:
move.l 4(sp),Cur_Match ; stack arg to register
IFD ATSIGN
@longest_match:
ENDC
movem.l SAVEREGS,-(sp)
; setup steps common to byte and word versions:
move.l _max_chain_length,Chain_Length
move.l _prev_length,Best_Len
lea _prev,Prev_Address
lea _window,Match_Ini
move.l _strstart,Limit
move.l Match_Ini,Scan_Ini
addq #MIN_MATCH,Match_Ini
add.l Limit,Scan_Ini
subi.w #MAX_DIST,Limit
bhi.s limit_ok
moveq #0,Limit
limit_ok:
cmp.l _good_match,Best_Len
bcs.s length_ok
lsr.l #2,Chain_Length
length_ok:
subq.l #1,Chain_Length
IFD CPUTEST
tst.w is020 ; can we use '020 stuff today?
bne WORD_match
ENDC
IFND CPU020
; for 68000 or 68010, use byte operations:
moveq #0,Scan_Start ; clear 2nd and 4th bytes, use 1st & 3rd
moveq #0,Scan_End
moveq #0,Scan_Test
move.b (Scan_Ini),Scan_Start
swap Scan_Start
move.b 1(Scan_Ini),Scan_Start
move.b -1(Scan_Ini,Best_Len),Scan_End
swap Scan_End
move.b 0(Scan_Ini,Best_Len),Scan_End
bra.s bdo_scan
blong_loop:
move.b -1(Scan_Ini,Best_Len),Scan_End
swap Scan_End
move.b 0(Scan_Ini,Best_Len),Scan_End
bshort_loop:
add.w Cur_Match,Cur_Match
move.w 0(Prev_Address,Cur_Match.l),Cur_Match
cmp.l Limit,Cur_Match
dbls Chain_Length,bdo_scan
bra return
bdo_scan:
move.l Match_Ini,Match
add.l Cur_Match,Match
move.b -MIN_MATCH-1(Match,Best_Len),Scan_Test
swap Scan_Test
move.b -MIN_MATCH(Match,Best_Len),Scan_Test
cmp.l Scan_Test,Scan_End
bne.s bshort_loop
move.b -MIN_MATCH(Match),Scan_Test
swap Scan_Test
move.b -MIN_MATCH+1(Match),Scan_Test
cmp.l Scan_Test,Scan_Start
bne.s bshort_loop
move.w #(MAX_MATCH-MIN_MATCH),Scan_Test
lea MIN_MATCH(Scan_Ini),Scan
bscan_loop:
cmpm.b (Match)+,(Scan)+
dbne Scan_Test,bscan_loop
subq #1,Scan
sub.l Scan_Ini,Scan
cmp.l Best_Len,Scan
bls.s bshort_loop
move.l Scan,Best_Len
move.l Cur_Match,_match_start
cmp.l _nice_match,Best_Len
bcs.s blong_loop
IFD CPUTEST
bra return
ENDC
ENDC ; !CPU020
IFND CPU000
; for 68020 or higher, use word operations even on odd addresses:
WORD_match:
move.w (Scan_Ini),Scan_Start
move.w -1(Scan_Ini,Best_Len),Scan_End
bra.s wdo_scan
wlong_loop:
move.w -1(Scan_Ini,Best_Len),Scan_End
wshort_loop:
add.w Cur_Match,Cur_Match
move.w (Prev_Address,Cur_Match.l),Cur_Match
cmp.l Limit,Cur_Match
dbls Chain_Length,wdo_scan
bra.s return
wdo_scan:
move.l Match_Ini,Match
add.l Cur_Match,Match
cmp.w -MIN_MATCH-1(Match,Best_Len),Scan_End
bne.s wshort_loop
cmp.w -MIN_MATCH(Match),Scan_Start
bne.s wshort_loop
moveq #((MAX_MATCH-MIN_MATCH)/2),Scan_Test ; value = 127
lea MIN_MATCH(Scan_Ini),Scan
wscan_loop:
cmpm.w (Match)+,(Scan)+
dbne Scan_Test,wscan_loop
subq #2,Scan
move.b -MIN_MATCH+1(Match),Scan_Test
cmp.b (Scan),Scan_Test
bne steven
addq #1,Scan
steven:
sub.l Scan_Ini,Scan
cmp.l Best_Len,Scan
bls.s wshort_loop
move.l Scan,Best_Len
move.l Cur_Match,_match_start
cmp.l _nice_match,Best_Len
bcs.s wlong_loop
ENDC ; !CPU000
return:
move.l Best_Len,d0 ; function return value
movem.l (sp)+,SAVEREGS
rts
end